package com.mentalhealthplatform.exception;

import com.mentalhealthplatform.exception.others.TooManyRequestsException;
import com.mentalhealthplatform.exception.user.UserAlreadyExistsException;
import com.mentalhealthplatform.exception.user.UserNotFoundException;
import com.mentalhealthplatform.exception.user.UserRegistrationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    private final DatabaseExceptionHandler databaseExceptionHandler;

    public GlobalExceptionHandler(DatabaseExceptionHandler databaseExceptionHandler) {
        this.databaseExceptionHandler = databaseExceptionHandler;
    }

    // 处理数据库异常
    @ExceptionHandler(DataAccessException.class)
    public ResponseEntity<ErrorResponse> handleDatabaseException(DataAccessException e) {
        logger.error("Database exception occurred");
        return databaseExceptionHandler.handleDatabaseException(e);
    }

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<?> handleUserNotFoundException(UserNotFoundException ex) {
        return buildErrorResponse("USER_NOT_FOUND", ex.getMessage(), HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(UserAlreadyExistsException.class)
    public ResponseEntity<?> handleUserAlreadyExistsException(UserAlreadyExistsException ex) {
        return buildErrorResponse("USER_ALREADY_EXISTS", ex.getMessage(), HttpStatus.CONFLICT);
    }

    @ExceptionHandler(UserRegistrationException.class)
    public ResponseEntity<?> handleUserRegistrationException(UserRegistrationException ex, WebRequest request) {
        return buildErrorResponse("USER_REGISTRATION_ERROR", ex.getMessage(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler({AuthenticationException.class, AccessDeniedException.class})
    public ResponseEntity<?> handleSecurityExceptions(RuntimeException ex, WebRequest request) {
        String message = ex instanceof AuthenticationException ? "Invalid username or password" : "Access denied";
        HttpStatus status = ex instanceof AuthenticationException ? HttpStatus.UNAUTHORIZED : HttpStatus.FORBIDDEN;
        return buildErrorResponse("SECURITY_ERROR", message, status);
    }


    @ExceptionHandler(TooManyRequestsException.class)
    public ResponseEntity<String> handleTooManyRequestsException(TooManyRequestsException ex) {
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<?> handleValidationException(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error -> {
            errors.put(error.getField(), error.getDefaultMessage());
        });
        Map<String, Object> response = new HashMap<>();
        response.put("code", "VALIDATION_ERROR");
        response.put("message", "Invalid input.");
        response.put("details", errors);
        response.put("status", HttpStatus.BAD_REQUEST.value());
        response.put("timestamp", System.currentTimeMillis());
        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }


    // 捕获其他通用异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneralException(Exception e) {
        logger.error("General exception occurred", e.getMessage(), e);
        return buildErrorResponse(e.getClass().getSimpleName(), e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    // 单例方法动态处理异常
    public ResponseEntity<ErrorResponse> processException(Throwable throwable) {

        // 使用日志记录异常信息
        logger.error("Exception occurred: ", throwable);

        // 创建 ErrorResponse 对象
        ErrorResponse errorResponse = new ErrorResponse(
                throwable.getClass().getSimpleName(),
                throwable.getMessage(),
                HttpStatus.INTERNAL_SERVER_ERROR.value(),
                LocalDateTime.now()
        );

        // 根据 throwable 的不同类型，可以修改 errorResponse 的内容
        if (throwable instanceof BadCredentialsException) {
            errorResponse.setError("UNAUTHORIZED");
            errorResponse.setMessage("用户名或密码错误");
            errorResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
        } else if (throwable instanceof DataAccessException) {
            return handleDatabaseException((DataAccessException) throwable);
        }

        // 其他异常类型的处理逻辑可以根据需要进一步扩展



        return ResponseEntity.status(HttpStatus.valueOf(errorResponse.getStatus())).body(errorResponse);
    }


    // 处理通用的错误响应构建
    private ResponseEntity<ErrorResponse> buildErrorResponse(String error, String detail, HttpStatus status) {
        logger.error("Error Response: [{}] - Detail: {}", error, detail);
        ErrorResponse errorResponse = new ErrorResponse(error, detail, status.value(), LocalDateTime.now());
        return new ResponseEntity<>(errorResponse, status);
    }
}
